///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __GpuProgramParams_H_
#define __GpuProgramParams_H_

// Precompiler options
#include "OgrePrerequisites.h"
#include "OgreSharedPtr.h"
#include "OgreIteratorWrappers.h"
#include "OgreSerializer.h"
#include "OgreRenderOperation.h"
#include "OgreAny.h"

namespace Ogre {


	enum GpuConstantType
	{
		GCT_FLOAT1 = 1,
		GCT_FLOAT2 = 2,
		GCT_FLOAT3 = 3,
		GCT_FLOAT4 = 4,
		GCT_SAMPLER1D = 5,
		GCT_SAMPLER2D = 6,
		GCT_SAMPLER3D = 7,
		GCT_SAMPLERCUBE = 8,
		GCT_SAMPLER1DSHADOW = 9,
		GCT_SAMPLER2DSHADOW = 10,
		GCT_MATRIX_2X2 = 11,
		GCT_MATRIX_2X3 = 12,
		GCT_MATRIX_2X4 = 13,
		GCT_MATRIX_3X2 = 14,
		GCT_MATRIX_3X3 = 15,
		GCT_MATRIX_3X4 = 16,
		GCT_MATRIX_4X2 = 17,
		GCT_MATRIX_4X3 = 18,
		GCT_MATRIX_4X4 = 19,
		GCT_INT1 = 20,
		GCT_INT2 = 21,
		GCT_INT3 = 22,
		GCT_INT4 = 23,
		GCT_UNKNOWN = 99
	};

	
	enum GpuParamVariability
	{
		/// No variation except by manual setting - the default
		GPV_GLOBAL = 1, 
		/// Varies per object (based on an auto param usually), but not per light setup
		GPV_PER_OBJECT = 2, 
		/// Varies with light setup
		GPV_LIGHTS = 4, 
		/// Varies with pass iteration number
		GPV_PASS_ITERATION_NUMBER = 8,


		/// Full mask (16-bit)
		GPV_ALL = 0xFFFF

	};

	
	struct _OgreExport GpuConstantDefinition
	{
		/// Data type
		GpuConstantType constType;
		/// Physical start index in buffer (either float or int buffer)
		size_t physicalIndex;
		/// Logical index - used to communicate this constant to the rendersystem
		size_t logicalIndex;
		
		size_t elementSize;
		/// Length of array
		size_t arraySize;
		/// How this parameter varies (bitwise combination of GpuProgramVariability)
		mutable uint16 variability;

		bool isFloat() const
		{
			return isFloat(constType);
		}

		static bool isFloat(GpuConstantType c)
		{
			switch(c)
			{
			case GCT_INT1:
			case GCT_INT2:
			case GCT_INT3:
			case GCT_INT4:
			case GCT_SAMPLER1D:
			case GCT_SAMPLER2D:
			case GCT_SAMPLER3D:
			case GCT_SAMPLERCUBE:
			case GCT_SAMPLER1DSHADOW:
			case GCT_SAMPLER2DSHADOW:
				return false;
			default:
				return true;
			};

		}

		bool isSampler() const
		{
			return isSampler(constType);
		}

		static bool isSampler(GpuConstantType c)
		{
			switch(c)
			{
			case GCT_SAMPLER1D:
			case GCT_SAMPLER2D:
			case GCT_SAMPLER3D:
			case GCT_SAMPLERCUBE:
			case GCT_SAMPLER1DSHADOW:
			case GCT_SAMPLER2DSHADOW:
				return true;
			default:
				return false;
			};

		}


		
		static size_t getElementSize(GpuConstantType ctype, bool padToMultiplesOf4)
		{
			if (padToMultiplesOf4)
			{
				switch(ctype)
				{
				case GCT_FLOAT1:
				case GCT_INT1:
				case GCT_SAMPLER1D:
				case GCT_SAMPLER2D:
				case GCT_SAMPLER3D:
				case GCT_SAMPLERCUBE:
				case GCT_SAMPLER1DSHADOW:
				case GCT_SAMPLER2DSHADOW:
				case GCT_FLOAT2:
				case GCT_INT2:
				case GCT_FLOAT3:
				case GCT_INT3:
				case GCT_FLOAT4:
				case GCT_INT4:
					return 4;
				case GCT_MATRIX_2X2:
				case GCT_MATRIX_2X3:
				case GCT_MATRIX_2X4:
					return 8; // 2 float4s
				case GCT_MATRIX_3X2:
				case GCT_MATRIX_3X3:
				case GCT_MATRIX_3X4:
					return 12; // 3 float4s
				case GCT_MATRIX_4X2:
				case GCT_MATRIX_4X3:
				case GCT_MATRIX_4X4:
					return 16; // 4 float4s
				default:
					return 4;
				};
			}
			else
			{
				switch(ctype)
				{
				case GCT_FLOAT1:
				case GCT_INT1:
				case GCT_SAMPLER1D:
				case GCT_SAMPLER2D:
				case GCT_SAMPLER3D:
				case GCT_SAMPLERCUBE:
				case GCT_SAMPLER1DSHADOW:
				case GCT_SAMPLER2DSHADOW:
					return 1;
				case GCT_FLOAT2:
				case GCT_INT2:
					return 2;
				case GCT_FLOAT3:
				case GCT_INT3:
					return 3;
				case GCT_FLOAT4:
				case GCT_INT4:
					return 4;
				case GCT_MATRIX_2X2:
					return 4;
				case GCT_MATRIX_2X3:
				case GCT_MATRIX_3X2:
					return 6;
				case GCT_MATRIX_2X4:
				case GCT_MATRIX_4X2:
					return 8; 
				case GCT_MATRIX_3X3:
					return 9;
				case GCT_MATRIX_3X4:
				case GCT_MATRIX_4X3:
					return 12; 
				case GCT_MATRIX_4X4:
					return 16; 
				default:
					return 4;
				};

			}
		}

		GpuConstantDefinition()
			: constType(GCT_UNKNOWN)
			, physicalIndex((std::numeric_limits<size_t>::max)())
			, elementSize(0)
			, arraySize(1)
			, variability(GPV_GLOBAL) {}
	};
	typedef map<String, GpuConstantDefinition>::type GpuConstantDefinitionMap;
	typedef ConstMapIterator<GpuConstantDefinitionMap> GpuConstantDefinitionIterator;

	/// Struct collecting together the information for named constants.
	struct _OgreExport GpuNamedConstants : public MemAlloc_RenderSys
	{
		/// Total size of the float buffer required
		size_t floatBufferSize;
		/// Total size of the int buffer required
		size_t intBufferSize;
		/// Map of parameter names to GpuConstantDefinition
		GpuConstantDefinitionMap map;

		GpuNamedConstants() : floatBufferSize(0), intBufferSize(0) {}

		
		void generateConstantDefinitionArrayEntries(const String& paramName, 
			const GpuConstantDefinition& baseDef);

		/// Indicates whether all array entries will be generated and added to the definitions map
		static bool getGenerateAllConstantDefinitionArrayEntries();

		
		static void setGenerateAllConstantDefinitionArrayEntries(bool generateAll);

		
		void save(const String& filename) const;
		
		void load(DataStreamPtr& stream);

	protected:
		
		static bool msGenerateAllConstantDefinitionArrayEntries;
	};
	typedef SharedPtr<GpuNamedConstants> GpuNamedConstantsPtr;

	/// Simple class for loading / saving GpuNamedConstants
	class _OgreExport GpuNamedConstantsSerializer : public Serializer
	{
	public:
		GpuNamedConstantsSerializer();
		virtual ~GpuNamedConstantsSerializer();
		void exportNamedConstants(const GpuNamedConstants* pConsts, const String& filename,
			Endian endianMode = ENDIAN_NATIVE);
		void exportNamedConstants(const GpuNamedConstants* pConsts, DataStreamPtr stream,
			Endian endianMode = ENDIAN_NATIVE);
		void importNamedConstants(DataStreamPtr& stream, GpuNamedConstants* pDest);
	};

	
	struct _OgreExport GpuLogicalIndexUse
	{
		/// Physical buffer index
		size_t physicalIndex;
		/// Current physical size allocation
		size_t currentSize;
		/// How the contents of this slot vary
		mutable uint16 variability;

		GpuLogicalIndexUse() 
			: physicalIndex(99999), currentSize(0), variability(GPV_GLOBAL) {}
		GpuLogicalIndexUse(size_t bufIdx, size_t curSz, uint16 v) 
			: physicalIndex(bufIdx), currentSize(curSz), variability(v) {}
	};
	typedef map<size_t, GpuLogicalIndexUse>::type GpuLogicalIndexUseMap;
	/// Container struct to allow params to safely & update shared list of logical buffer assignments
	struct _OgreExport GpuLogicalBufferStruct : public MemAlloc_RenderSys
	{
		OGRE_MUTEX(mutex)
			/// Map from logical index to physical buffer location
			GpuLogicalIndexUseMap map;
		/// Shortcut to know the buffer size needs
		size_t bufferSize;
		GpuLogicalBufferStruct() : bufferSize(0) {}
	};
	typedef SharedPtr<GpuLogicalBufferStruct> GpuLogicalBufferStructPtr;

	
	typedef vector<float>::type FloatConstantList;
	
	typedef vector<int>::type IntConstantList;

	
	class _OgreExport GpuSharedParameters : public MemAlloc_RenderSys
	{
	protected:
		GpuNamedConstants mNamedConstants;
		FloatConstantList mFloatConstants;
		IntConstantList mIntConstants;
		String mName;

		// Optional data the rendersystem might want to store
		mutable Any mRenderSystemData;

		/// Not used when copying data, but might be useful to RS using shared buffers
		size_t mFrameLastUpdated;

		/// Version number of the definitions in this buffer
		unsigned long mVersion; 

	public:
		GpuSharedParameters(const String& name);
		virtual ~GpuSharedParameters();

		/// Get the name of this shared parameter set
		const String& getName() { return mName; }

		
		void addConstantDefinition(const String& name, GpuConstantType constType, size_t arraySize = 1);

		
		void removeConstantDefinition(const String& name);

		
		void removeAllConstantDefinitions();

		
		unsigned long getVersion() const { return mVersion; }

		
		void _markDirty();
		/// Get the frame in which this shared parameter set was last updated
		size_t getFrameLastUpdated() const { return mFrameLastUpdated; }

		
		GpuConstantDefinitionIterator getConstantDefinitionIterator(void) const;

		
		const GpuConstantDefinition& getConstantDefinition(const String& name) const;

		
		const GpuNamedConstants& getConstantDefinitions() const;
	
		
		void setNamedConstant(const String& name, Real val);
		
		void setNamedConstant(const String& name, int val);
		
		void setNamedConstant(const String& name, const Vector4& vec);
		
		void setNamedConstant(const String& name, const Vector3& vec);
		
		void setNamedConstant(const String& name, const Matrix4& m);
		
		void setNamedConstant(const String& name, const Matrix4* m, size_t numEntries);
		
		void setNamedConstant(const String& name, const float *val, size_t count);
		
		void setNamedConstant(const String& name, const double *val, size_t count);
			
		void setNamedConstant(const String& name, const ColourValue& colour);
		
		void setNamedConstant(const String& name, const int *val, size_t count);

		/// Get a pointer to the 'nth' item in the float buffer
		float* getFloatPointer(size_t pos) { _markDirty(); return &mFloatConstants[pos]; }
		/// Get a pointer to the 'nth' item in the float buffer
		const float* getFloatPointer(size_t pos) const { return &mFloatConstants[pos]; }
		/// Get a pointer to the 'nth' item in the int buffer
		int* getIntPointer(size_t pos) { _markDirty(); return &mIntConstants[pos]; }
		/// Get a pointer to the 'nth' item in the int buffer
		const int* getIntPointer(size_t pos) const { return &mIntConstants[pos]; }


		
		void _setRenderSystemData(const Any& data) const { mRenderSystemData = data; }
		
		const Any& _getRenderSystemData() const { return mRenderSystemData; }

	};

	/// Shared pointer used to hold references to GpuProgramParameters instances
	typedef SharedPtr<GpuSharedParameters> GpuSharedParametersPtr;

	class GpuProgramParameters;

	
	class _OgreExport GpuSharedParametersUsage : public MemAlloc_RenderSys
	{
	protected:
		GpuSharedParametersPtr mSharedParams;
		// Not a shared pointer since this is also parent
		GpuProgramParameters* mParams;
		// list of physical mappings that we are going to bring in
		struct CopyDataEntry
		{
			const GpuConstantDefinition* srcDefinition;
			const GpuConstantDefinition* dstDefinition;
		};
		typedef vector<CopyDataEntry>::type CopyDataList;

		CopyDataList mCopyDataList;

		// Optional data the rendersystem might want to store
		mutable Any mRenderSystemData;

		/// Version of shared params we based the copydata on
		unsigned long mCopyDataVersion;

		void initCopyData();


	public:
		/// Construct usage
		GpuSharedParametersUsage(GpuSharedParametersPtr sharedParams, 
			GpuProgramParameters* params);

		
		void _copySharedParamsToTargetParams();

		/// Get the name of the shared parameter set
		const String& getName() const { return mSharedParams->getName(); }

		GpuSharedParametersPtr getSharedParams() const { return mSharedParams; }
		GpuProgramParameters* getTargetParams() const { return mParams; }

		
		void _setRenderSystemData(const Any& data) const { mRenderSystemData = data; }
		
		const Any& _getRenderSystemData() const { return mRenderSystemData; }


	};

	
	class _OgreExport GpuProgramParameters : public MemAlloc_RenderSys
	{
	public:
		
		enum AutoConstantType
		{
			/// The current world matrix
			ACT_WORLD_MATRIX,
			/// The current world matrix, inverted
			ACT_INVERSE_WORLD_MATRIX,
			
			ACT_TRANSPOSE_WORLD_MATRIX,
			/// The current world matrix, inverted & transposed
			ACT_INVERSE_TRANSPOSE_WORLD_MATRIX,

			/// The current array of world matrices, as a 3x4 matrix, used for blending
			ACT_WORLD_MATRIX_ARRAY_3x4,
			/// The current array of world matrices, used for blending
			ACT_WORLD_MATRIX_ARRAY,
			/// The current array of world matrices transformed to an array of dual quaternions, represented as a 2x4 matrix
			ACT_WORLD_DUALQUATERNION_ARRAY_2x4,
			/// The scale and shear components of the current array of world matrices
			ACT_WORLD_SCALE_SHEAR_MATRIX_ARRAY_3x4,
			
			/// The current view matrix
			ACT_VIEW_MATRIX,
			/// The current view matrix, inverted
			ACT_INVERSE_VIEW_MATRIX,
			
			ACT_TRANSPOSE_VIEW_MATRIX,
			
			ACT_INVERSE_TRANSPOSE_VIEW_MATRIX,


			/// The current projection matrix
			ACT_PROJECTION_MATRIX,
			
			ACT_INVERSE_PROJECTION_MATRIX,
			
			ACT_TRANSPOSE_PROJECTION_MATRIX,
			
			ACT_INVERSE_TRANSPOSE_PROJECTION_MATRIX,


			/// The current view & projection matrices concatenated
			ACT_VIEWPROJ_MATRIX,
			
			ACT_INVERSE_VIEWPROJ_MATRIX,
			
			ACT_TRANSPOSE_VIEWPROJ_MATRIX,
			
			ACT_INVERSE_TRANSPOSE_VIEWPROJ_MATRIX,


			/// The current world & view matrices concatenated
			ACT_WORLDVIEW_MATRIX,
			/// The current world & view matrices concatenated, then inverted
			ACT_INVERSE_WORLDVIEW_MATRIX,
			
			ACT_TRANSPOSE_WORLDVIEW_MATRIX,
			/// The current world & view matrices concatenated, then inverted & transposed
			ACT_INVERSE_TRANSPOSE_WORLDVIEW_MATRIX,
			/// view matrices.


			/// The current world, view & projection matrices concatenated
			ACT_WORLDVIEWPROJ_MATRIX,
			
			ACT_INVERSE_WORLDVIEWPROJ_MATRIX,
			
			ACT_TRANSPOSE_WORLDVIEWPROJ_MATRIX,
			
			ACT_INVERSE_TRANSPOSE_WORLDVIEWPROJ_MATRIX,


			/// render target related values
			
			ACT_RENDER_TARGET_FLIPPING,

			
			ACT_VERTEX_WINDING,

			/// Fog colour
			ACT_FOG_COLOUR,
			/// Fog params: density, linear start, linear end, 1/(end-start)
			ACT_FOG_PARAMS,


			/// Surface ambient colour, as set in Pass::setAmbient
			ACT_SURFACE_AMBIENT_COLOUR,
			/// Surface diffuse colour, as set in Pass::setDiffuse
			ACT_SURFACE_DIFFUSE_COLOUR,
			/// Surface specular colour, as set in Pass::setSpecular
			ACT_SURFACE_SPECULAR_COLOUR,
			/// Surface emissive colour, as set in Pass::setSelfIllumination
			ACT_SURFACE_EMISSIVE_COLOUR,
			/// Surface shininess, as set in Pass::setShininess
			ACT_SURFACE_SHININESS,


			/// The number of active light sources (better than gl_MaxLights)
			ACT_LIGHT_COUNT,


			/// The ambient light colour set in the scene
			ACT_AMBIENT_LIGHT_COLOUR, 

			/// Light diffuse colour (index determined by setAutoConstant call)
			ACT_LIGHT_DIFFUSE_COLOUR,
			/// Light specular colour (index determined by setAutoConstant call)
			ACT_LIGHT_SPECULAR_COLOUR,
			/// Light attenuation parameters, Vector4(range, constant, linear, quadric)
			ACT_LIGHT_ATTENUATION,
			 
			ACT_SPOTLIGHT_PARAMS,
			/// A light position in world space (index determined by setAutoConstant call)
			ACT_LIGHT_POSITION,
			/// A light position in object space (index determined by setAutoConstant call)
			ACT_LIGHT_POSITION_OBJECT_SPACE,
			/// A light position in view space (index determined by setAutoConstant call)
			ACT_LIGHT_POSITION_VIEW_SPACE,
			/// A light direction in world space (index determined by setAutoConstant call)
			ACT_LIGHT_DIRECTION,
			/// A light direction in object space (index determined by setAutoConstant call)
			ACT_LIGHT_DIRECTION_OBJECT_SPACE,
			/// A light direction in view space (index determined by setAutoConstant call)
			ACT_LIGHT_DIRECTION_VIEW_SPACE,
			
			ACT_LIGHT_DISTANCE_OBJECT_SPACE,
			
			ACT_LIGHT_POWER_SCALE,
			/// Light diffuse colour pre-scaled by Light::setPowerScale (index determined by setAutoConstant call)
			ACT_LIGHT_DIFFUSE_COLOUR_POWER_SCALED,
			/// Light specular colour pre-scaled by Light::setPowerScale (index determined by setAutoConstant call)
			ACT_LIGHT_SPECULAR_COLOUR_POWER_SCALED,
			/// Array of light diffuse colours (count set by extra param)
			ACT_LIGHT_DIFFUSE_COLOUR_ARRAY,
			/// Array of light specular colours (count set by extra param)
			ACT_LIGHT_SPECULAR_COLOUR_ARRAY,
			/// Array of light diffuse colours scaled by light power (count set by extra param)
			ACT_LIGHT_DIFFUSE_COLOUR_POWER_SCALED_ARRAY,
			/// Array of light specular colours scaled by light power (count set by extra param)
			ACT_LIGHT_SPECULAR_COLOUR_POWER_SCALED_ARRAY,
			/// Array of light attenuation parameters, Vector4(range, constant, linear, quadric) (count set by extra param)
			ACT_LIGHT_ATTENUATION_ARRAY,
			/// Array of light positions in world space (count set by extra param)
			ACT_LIGHT_POSITION_ARRAY,
			/// Array of light positions in object space (count set by extra param)
			ACT_LIGHT_POSITION_OBJECT_SPACE_ARRAY,
			/// Array of light positions in view space (count set by extra param)
			ACT_LIGHT_POSITION_VIEW_SPACE_ARRAY,
			/// Array of light directions in world space (count set by extra param)
			ACT_LIGHT_DIRECTION_ARRAY,
			/// Array of light directions in object space (count set by extra param)
			ACT_LIGHT_DIRECTION_OBJECT_SPACE_ARRAY,
			/// Array of light directions in view space (count set by extra param)
			ACT_LIGHT_DIRECTION_VIEW_SPACE_ARRAY,
			
			ACT_LIGHT_DISTANCE_OBJECT_SPACE_ARRAY,
			
			ACT_LIGHT_POWER_SCALE_ARRAY,
			 
			ACT_SPOTLIGHT_PARAMS_ARRAY,

			
			ACT_DERIVED_AMBIENT_LIGHT_COLOUR,
			
			ACT_DERIVED_SCENE_COLOUR,

			
			ACT_DERIVED_LIGHT_DIFFUSE_COLOUR,
			
			ACT_DERIVED_LIGHT_SPECULAR_COLOUR,

			/// Array of derived light diffuse colours (count set by extra param)
			ACT_DERIVED_LIGHT_DIFFUSE_COLOUR_ARRAY,
			/// Array of derived light specular colours (count set by extra param)
			ACT_DERIVED_LIGHT_SPECULAR_COLOUR_ARRAY,
			
			ACT_LIGHT_NUMBER,
			/// Returns (int) 1 if the  given light casts shadows, 0 otherwise (index set in extra param)
			ACT_LIGHT_CASTS_SHADOWS,


			
			ACT_SHADOW_EXTRUSION_DISTANCE,
			/// The current camera's position in world space
			ACT_CAMERA_POSITION,
			/// The current camera's position in object space 
			ACT_CAMERA_POSITION_OBJECT_SPACE,
			/// The view/projection matrix of the assigned texture projection frustum
			ACT_TEXTURE_VIEWPROJ_MATRIX,
			/// Array of view/projection matrices of the first n texture projection frustums
			ACT_TEXTURE_VIEWPROJ_MATRIX_ARRAY,
			
			ACT_TEXTURE_WORLDVIEWPROJ_MATRIX,
			/// Array of world/view/projection matrices of the first n texture projection frustums
			ACT_TEXTURE_WORLDVIEWPROJ_MATRIX_ARRAY,
			/// The view/projection matrix of a given spotlight
			ACT_SPOTLIGHT_VIEWPROJ_MATRIX,
			/// Array of view/projection matrix of a given spotlight
			ACT_SPOTLIGHT_VIEWPROJ_MATRIX_ARRAY,
			
			ACT_SPOTLIGHT_WORLDVIEWPROJ_MATRIX,
			/// A custom parameter which will come from the renderable, using 'data' as the identifier
			ACT_CUSTOM,
			
			ACT_TIME,
			
			ACT_TIME_0_X,
			/// Cosine of "Time0_X". Equivalent to RenderMonkey's "CosTime0_X".
			ACT_COSTIME_0_X,
			/// Sine of "Time0_X". Equivalent to RenderMonkey's "SinTime0_X".
			ACT_SINTIME_0_X,
			/// Tangent of "Time0_X". Equivalent to RenderMonkey's "TanTime0_X".
			ACT_TANTIME_0_X,
			
			ACT_TIME_0_X_PACKED,
			
			ACT_TIME_0_1,
			/// Cosine of "Time0_1". Equivalent to RenderMonkey's "CosTime0_1".
			ACT_COSTIME_0_1,
			/// Sine of "Time0_1". Equivalent to RenderMonkey's "SinTime0_1".
			ACT_SINTIME_0_1,
			/// Tangent of "Time0_1". Equivalent to RenderMonkey's "TanTime0_1".
			ACT_TANTIME_0_1,
			
			ACT_TIME_0_1_PACKED,
			/**	Single float value, which represents scaled time value [0..2*Pi],
			which repeats itself based on given as parameter "cycle time".
			Equivalent to RenderMonkey's "Time0_2PI".
			*/
			ACT_TIME_0_2PI,
			/// Cosine of "Time0_2PI". Equivalent to RenderMonkey's "CosTime0_2PI".
			ACT_COSTIME_0_2PI,
			/// Sine of "Time0_2PI". Equivalent to RenderMonkey's "SinTime0_2PI".
			ACT_SINTIME_0_2PI,
			/// Tangent of "Time0_2PI". Equivalent to RenderMonkey's "TanTime0_2PI".
			ACT_TANTIME_0_2PI,
			
			ACT_TIME_0_2PI_PACKED,
			/// provides the scaled frame time, returned as a floating point value.
			ACT_FRAME_TIME,
			/// provides the calculated frames per second, returned as a floating point value.
			ACT_FPS,
			/// viewport-related values
			
			ACT_VIEWPORT_WIDTH,
			
			ACT_VIEWPORT_HEIGHT,
			
			ACT_INVERSE_VIEWPORT_WIDTH,
			
			ACT_INVERSE_VIEWPORT_HEIGHT,
			
			ACT_VIEWPORT_SIZE,

			/// view parameters
			
			ACT_VIEW_DIRECTION,
			
			ACT_VIEW_SIDE_VECTOR,
			
			ACT_VIEW_UP_VECTOR,
			
			ACT_FOV,
			/**	This variable provides the near clip distance as a floating point value.
			Equivalent to RenderMonkey's "NearClipPlane".
			*/
			ACT_NEAR_CLIP_DISTANCE,
			/**	This variable provides the far clip distance as a floating point value.
			Equivalent to RenderMonkey's "FarClipPlane".
			*/
			ACT_FAR_CLIP_DISTANCE,

			
			ACT_PASS_NUMBER,

			
			ACT_PASS_ITERATION_NUMBER,


			
			ACT_ANIMATION_PARAMETRIC,

			
			ACT_TEXEL_OFFSETS,

			
			ACT_SCENE_DEPTH_RANGE,

			
			ACT_SHADOW_SCENE_DEPTH_RANGE,

			
			ACT_SHADOW_COLOUR,
			
			ACT_TEXTURE_SIZE,
			
			ACT_INVERSE_TEXTURE_SIZE,
			
			ACT_PACKED_TEXTURE_SIZE,

			
			ACT_TEXTURE_MATRIX, 

			
			ACT_LOD_CAMERA_POSITION, 
			
			ACT_LOD_CAMERA_POSITION_OBJECT_SPACE, 
			
			ACT_LIGHT_CUSTOM
		};

		
		enum ACDataType {
			/// no data is required
			ACDT_NONE,
			/// the auto constant requires data of type int
			ACDT_INT,
			/// the auto constant requires data of type real
			ACDT_REAL
		};

		
		enum ElementType {
			ET_INT,
			ET_REAL
		};

		
		struct AutoConstantDefinition
		{
			AutoConstantType acType;
			String name;
			size_t elementCount;
			/// The type of the constant in the program
			ElementType elementType;
			/// The type of any extra data
			ACDataType dataType;

			AutoConstantDefinition(AutoConstantType _acType, const String& _name, 
				size_t _elementCount, ElementType _elementType, 
				ACDataType _dataType)
				:acType(_acType), name(_name), elementCount(_elementCount), 
				elementType(_elementType), dataType(_dataType)
			{

			}
		};

		
		class AutoConstantEntry
		{
		public:
			/// The type of parameter
			AutoConstantType paramType;
			/// The target (physical) constant index
			size_t physicalIndex;
			
			size_t elementCount;
			/// Additional information to go with the parameter
			union{
				size_t data;
				Real fData;
			};
			/// The variability of this parameter (see GpuParamVariability)
			uint16 variability;

			AutoConstantEntry(AutoConstantType theType, size_t theIndex, size_t theData, 
				uint16 theVariability, size_t theElemCount = 4)
				: paramType(theType), physicalIndex(theIndex), elementCount(theElemCount), 
				data(theData), variability(theVariability) {}

			AutoConstantEntry(AutoConstantType theType, size_t theIndex, Real theData, 
				uint16 theVariability, size_t theElemCount = 4)
				: paramType(theType), physicalIndex(theIndex), elementCount(theElemCount), 
				fData(theData), variability(theVariability) {}

		};
		// Auto parameter storage
		typedef vector<AutoConstantEntry>::type AutoConstantList;

		typedef vector<GpuSharedParametersUsage>::type GpuSharedParamUsageList;

	protected:
		static AutoConstantDefinition AutoConstantDictionary[];
		/// Packed list of floating-point constants (physical indexing)
		FloatConstantList mFloatConstants;
		/// Packed list of integer constants (physical indexing)
		IntConstantList mIntConstants;
		
		GpuLogicalBufferStructPtr mFloatLogicalToPhysical;
		
		GpuLogicalBufferStructPtr mIntLogicalToPhysical;
		/// Mapping from parameter names to def - high-level programs are expected to populate this
		GpuNamedConstantsPtr mNamedConstants;
		/// List of automatically updated parameters
		AutoConstantList mAutoConstants;
		/// The combined variability masks of all parameters
		uint16 mCombinedVariability;
		/// Do we need to transpose matrices?
		bool mTransposeMatrices;
		/// flag to indicate if names not found will be ignored
		bool mIgnoreMissingParams;
		/// physical index for active pass iteration parameter real constant entry;
		size_t mActivePassIterationIndex;

		
		GpuLogicalIndexUse* _getFloatConstantLogicalIndexUse(size_t logicalIndex, size_t requestedSize, uint16 variability);
		
		GpuLogicalIndexUse* _getIntConstantLogicalIndexUse(size_t logicalIndex, size_t requestedSize, uint16 variability);

		/// Return the variability for an auto constant
		uint16 deriveVariability(AutoConstantType act);

		void copySharedParamSetUsage(const GpuSharedParamUsageList& srcList);

		GpuSharedParamUsageList mSharedParamSets;

		// Optional data the rendersystem might want to store
		mutable Any mRenderSystemData;



	public:
		GpuProgramParameters();
		~GpuProgramParameters() {}

		/// Copy constructor
		GpuProgramParameters(const GpuProgramParameters& oth);
		/// Operator = overload
		GpuProgramParameters& operator=(const GpuProgramParameters& oth);

		
		void _setNamedConstants(const GpuNamedConstantsPtr& constantmap);

		
		void _setLogicalIndexes(const GpuLogicalBufferStructPtr& floatIndexMap, 
			const GpuLogicalBufferStructPtr&  intIndexMap);


		/// Does this parameter set include named parameters?
		bool hasNamedParameters() const { return !mNamedConstants.isNull(); }
		
		bool hasLogicalIndexedParameters() const { return !mFloatLogicalToPhysical.isNull(); }

		
		void setConstant(size_t index, const Vector4& vec);
		
		void setConstant(size_t index, Real val);
		
		void setConstant(size_t index, const Vector3& vec);
		
		void setConstant(size_t index, const Matrix4& m);
		
		void setConstant(size_t index, const Matrix4* m, size_t numEntries);
		
		void setConstant(size_t index, const float *val, size_t count);
		
		void setConstant(size_t index, const double *val, size_t count);
		
		void setConstant(size_t index, const ColourValue& colour);

		
		void setConstant(size_t index, const int *val, size_t count);

		
		void _writeRawConstants(size_t physicalIndex, const float* val, size_t count);
		
		void _writeRawConstants(size_t physicalIndex, const double* val, size_t count);
		
		void _writeRawConstants(size_t physicalIndex, const int* val, size_t count);
		
		void _readRawConstants(size_t physicalIndex, size_t count, float* dest);
		
		void _readRawConstants(size_t physicalIndex, size_t count, int* dest);

		
		void _writeRawConstant(size_t physicalIndex, const Vector4& vec, 
			size_t count = 4);
		
		void _writeRawConstant(size_t physicalIndex, Real val);
		
		void _writeRawConstant(size_t physicalIndex, int val);
		
		void _writeRawConstant(size_t physicalIndex, const Vector3& vec);
		
		void _writeRawConstant(size_t physicalIndex, const Matrix4& m, size_t elementCount);
		
		void _writeRawConstant(size_t physicalIndex, const Matrix4* m, size_t numEntries);
		
		void _writeRawConstant(size_t physicalIndex, const ColourValue& colour, 
			size_t count = 4);


		
		GpuConstantDefinitionIterator getConstantDefinitionIterator(void) const;

		
		const GpuConstantDefinition& getConstantDefinition(const String& name) const;

		
		const GpuNamedConstants& getConstantDefinitions() const;

		
		const GpuLogicalBufferStructPtr& getFloatLogicalBufferStruct() const { return mFloatLogicalToPhysical; }

		
		size_t getFloatLogicalIndexForPhysicalIndex(size_t physicalIndex);
		
		size_t getIntLogicalIndexForPhysicalIndex(size_t physicalIndex);

		
		const GpuLogicalBufferStructPtr& getIntLogicalBufferStruct() const { return mIntLogicalToPhysical; }
		/// Get a reference to the list of float constants
		const FloatConstantList& getFloatConstantList() const { return mFloatConstants; }
		/// Get a pointer to the 'nth' item in the float buffer
		float* getFloatPointer(size_t pos) { return &mFloatConstants[pos]; }
		/// Get a pointer to the 'nth' item in the float buffer
		const float* getFloatPointer(size_t pos) const { return &mFloatConstants[pos]; }
		/// Get a reference to the list of int constants
		const IntConstantList& getIntConstantList() const { return mIntConstants; }
		/// Get a pointer to the 'nth' item in the int buffer
		int* getIntPointer(size_t pos) { return &mIntConstants[pos]; }
		/// Get a pointer to the 'nth' item in the int buffer
		const int* getIntPointer(size_t pos) const { return &mIntConstants[pos]; }
		/// Get a reference to the list of auto constant bindings
		const AutoConstantList& getAutoConstantList() const { return mAutoConstants; }

		
		void setAutoConstant(size_t index, AutoConstantType acType, size_t extraInfo = 0);
		void setAutoConstantReal(size_t index, AutoConstantType acType, Real rData);

		
		void setAutoConstant(size_t index, AutoConstantType acType, uint16 extraInfo1, uint16 extraInfo2);

		
		void _setRawAutoConstant(size_t physicalIndex, AutoConstantType acType, size_t extraInfo, 
			uint16 variability, size_t elementSize = 4);
		
		void _setRawAutoConstantReal(size_t physicalIndex, AutoConstantType acType, Real rData, 
			uint16 variability, size_t elementSize = 4);


		
		void clearAutoConstant(size_t index);

		  
		void setConstantFromTime(size_t index, Real factor);

		
		void clearAutoConstants(void);
		typedef ConstVectorIterator<AutoConstantList> AutoConstantIterator;
		
		AutoConstantIterator getAutoConstantIterator(void) const;
		/// Gets the number of int constants that have been set
		size_t getAutoConstantCount(void) const { return mAutoConstants.size(); }
		
		AutoConstantEntry* getAutoConstantEntry(const size_t index);
		
		bool hasAutoConstants(void) const { return !(mAutoConstants.empty()); }
		
		const AutoConstantEntry* findFloatAutoConstantEntry(size_t logicalIndex);
		
		const AutoConstantEntry* findIntAutoConstantEntry(size_t logicalIndex);
		
		const AutoConstantEntry* findAutoConstantEntry(const String& paramName);
		
		const AutoConstantEntry* _findRawAutoConstantEntryFloat(size_t physicalIndex);
		
		const AutoConstantEntry* _findRawAutoConstantEntryInt(size_t physicalIndex);

		
		void _updateAutoParams(const AutoParamDataSource* source, uint16 variabilityMask);

		
		void setIgnoreMissingParams(bool state) { mIgnoreMissingParams = state; }

		
		void setNamedConstant(const String& name, Real val);
		
		void setNamedConstant(const String& name, int val);
		
		void setNamedConstant(const String& name, const Vector4& vec);
		
		void setNamedConstant(const String& name, const Vector3& vec);
		
		void setNamedConstant(const String& name, const Matrix4& m);
		
		void setNamedConstant(const String& name, const Matrix4* m, size_t numEntries);
		
		void setNamedConstant(const String& name, const float *val, size_t count, 
			size_t multiple = 4);
		
		void setNamedConstant(const String& name, const double *val, size_t count, 
			size_t multiple = 4);
		
		void setNamedConstant(const String& name, const ColourValue& colour);

		
		void setNamedConstant(const String& name, const int *val, size_t count, 
			size_t multiple = 4);

		
		void setNamedAutoConstant(const String& name, AutoConstantType acType, size_t extraInfo = 0);
		void setNamedAutoConstantReal(const String& name, AutoConstantType acType, Real rData);

		
		void setNamedAutoConstant(const String& name, AutoConstantType acType, uint16 extraInfo1, uint16 extraInfo2);

		  
		void setNamedConstantFromTime(const String& name, Real factor);

		
		void clearNamedAutoConstant(const String& name);

		
		const GpuConstantDefinition* _findNamedConstantDefinition(
			const String& name, bool throwExceptionIfMissing = false) const;
		
		size_t _getFloatConstantPhysicalIndex(size_t logicalIndex, size_t requestedSize, uint16 variability);
		
		size_t _getIntConstantPhysicalIndex(size_t logicalIndex, size_t requestedSize, uint16 variability);

		
		void setTransposeMatrices(bool val) { mTransposeMatrices = val; } 
		/// Gets whether or not matrices are to be transposed when set
		bool getTransposeMatrices(void) const { return mTransposeMatrices; } 

		
		void copyConstantsFrom(const GpuProgramParameters& source);

		
		void copyMatchingNamedConstantsFrom(const GpuProgramParameters& source);

		
		static const AutoConstantDefinition* getAutoConstantDefinition(const String& name);
		
		static const AutoConstantDefinition* getAutoConstantDefinition(const size_t idx);
		
		static size_t getNumAutoConstantDefinitions(void);


		
		void incPassIterationNumber(void);
		
		bool hasPassIterationNumber() const 
		{ return mActivePassIterationIndex != (std::numeric_limits<size_t>::max)(); }
		
		size_t getPassIterationNumberIndex() const 
		{ return mActivePassIterationIndex; }


		
		void addSharedParameters(GpuSharedParametersPtr sharedParams);

		
		void addSharedParameters(const String& sharedParamsName);

		
		bool isUsingSharedParameters(const String& sharedParamsName) const;

		
		void removeSharedParameters(const String& sharedParamsName);

		
		void removeAllSharedParameters();

		
		const GpuSharedParamUsageList& getSharedParameters() const;

		
		void _setRenderSystemData(const Any& data) const { mRenderSystemData = data; }
		
		const Any& _getRenderSystemData() const { return mRenderSystemData; }

		
		void _copySharedParams();



	};

	/// Shared pointer used to hold references to GpuProgramParameters instances
	typedef SharedPtr<GpuProgramParameters> GpuProgramParametersSharedPtr;

	
	
}
#endif

